#include "unary_parser.h"
#include "composite_parser.h"

using namespace std;
using namespace eg;

#define min(x,y) ( (x<y)?x:y )
context::context * parser::the_context;

//==================================================================================================
//                                    Syntax Tree implementation
//==================================================================================================

ast::~ast() {
	// free childs

	for (list<ast *>::iterator i = childs.begin(); i != childs.end(); i++)
		delete *i;
}

void ast::push_child(ast * child) {
	childs.push_front(child);
}

ast * ast::get_child(int index) {
	list<ast *>::iterator it = childs.begin();
	int i = 0;
	while (it != childs.end() and i < index) {
		it++;
		i++;
	}
	return *it;
}

string ast::to_string() {
	string s = desc;
	if (not is_a_leaf())
		s += '(';
	for (list<ast *>::iterator it = childs.begin(); it != childs.end(); it++) {
		if (it != childs.begin())
			s += ',';
		s += (*it)->to_string();
	}
	if (not is_a_leaf())
		s += ')';
	return s;
}

//==================================================================================================
//                           context class implementation
//==================================================================================================
parser * context::disable_parser() {
	parser * aux_parser = skip_parser;
	skip_parser = NULL;
	return aux_parser;
}
void context::enable_parser(parser * aux_parser) {
	skip_parser = aux_parser;
}
//==================================================================================================
//                          parser base class (partial) implementation
//==================================================================================================

// Initial parsing function
ast * parser::do_parsing(istream & input, parser * skip_parser) {
	/*new_line * nl = new new_line();
	the_context->new_line_parser = nl; //always init new_line_parser*/

	semantic_stack s;
	the_context = new context(input);

	the_context->skip_parser = skip_parser; //initialize  skip_parser if is not null
	if (parse()) {
		cout<<"End parsing successfully "<< endl;
		if (!the_context->error_mode_by_mistake ||the_context->error_mode ){// esta mal esta condicion
			return 0;}

		s = the_context->s;
		delete the_context;
		return s.top();
	} else {
		// free partial build ast
		while (not the_context->s.empty()) {
			delete the_context->s.top();
			the_context->s.pop();
		}
		delete the_context;
		return 0;
	}
}
//=================================== Parsers creation methods =====================================

parser & parser::end_of_input() {
	return *(new eof());
}

parser & parser::a_char(char c) {
	return *(new a_char_parser(c));
}

parser & parser::some_char() {
	return *(new some_char_parser());
}

parser & parser::in(string s) {
	return *(new char_class_parser(s));
}

parser & parser::in(char from, char until) {
	return *(new char_range_parser(from, until));
}

parser & parser::a_word(string s) {
	return *(new a_string_parser(s));
}

parser & parser::not_a(parser & p) {
	return *(new not_parser(&p));
}

parser & parser::follows(parser & p) {
	return *(new and_parser(&p));
}

parser & parser::one_or_more(parser & p) {
	return *(new one_or_more_parser(&p));
}

parser & parser::zero_or_more(parser & p) {
	return *(new zero_or_more_parser(&p));
}

parser & parser::maybe(parser & p) {
	return *(new zero_or_one_parser(&p));
}

parser & parser::operator+(parser & p) {
	seq_parser * seq = new seq_parser();

	seq->add_parser(this);
	seq->add_parser(&p);
	return *seq;
}

parser & parser::operator|(parser & p) {
	alt_parser * alt = new alt_parser();

	alt->add_parser(this);
	alt->add_parser(&p);
	return *alt;
}
parser & parser::error(char rec_point, char look_ahead) {
	return *(new error_parser(rec_point, look_ahead));
}
//====================================== Parsing succeed ===========================================
bool parser::accept(string node_desc, int begin_pos, int childs) {

	the_context->acum_nl_counter += the_context->parcial_nl_counter;
					the_context->parcial_nl_counter = 0;
	if (!the_context->error_mode ) {
		if (not node_desc.empty()) {
			// build the tree. Childs are on stack
			ast * t = new ast(node_desc);

			// actualize new line counter


			t->set_begin_pos(begin_pos);
			for (int i = 0; i < childs; i++) {
				ast * child = the_context->s.top();
				t->push_child(child);
				the_context->s.pop();
			}
			the_context->s.push(t);
			//cout << t->to_string();
			t->set_end_pos(the_context->input.tellg());
			the_context->last_char_pos = the_context->input.tellg();
			/*cout << "begin_pos = " << t->get_begin_pos() << endl;
			 cout << "last _char = " << the_context->last_char_pos << endl;*/
		}
	}
	//cout << " accepted." << endl;
	return true;
}

//================================== Parsing failed: backtrack =====================================
bool parser::reject(pos_type back_to, int childs_to_free) {

	for (int i = 0; i < childs_to_free; i++) {
		delete the_context->s.top();
		the_context->s.pop();
	}
	the_context->input.seekg(back_to);
	the_context->parcial_nl_counter = 0;
	 //cout << "partial COUNTER " << the_context->parcial_nl_counter << endl;
	return false;
}

